export {};

//  三目运算 条件判断  extends表示是否为 次类型

interface Bird {
  name: "鸟";
}

interface Fish {
  name: "鱼";
}

interface Sky {
  name: "天空";
}

interface Water {
  name: "水";
}
type IChangeEnv<T extends Bird | Fish> = T extends Fish ? Water : Sky;
type IEnv = IChangeEnv<Fish>; // Water
// 为联合类型时  具有分发的能力
type IEnv1 = IChangeEnv<Fish | Bird>; // Water
// 泛型不为裸类型时 T被() []  不具备分发的能力
type IChangeEnv1<T extends Bird | Fish> = [T] extends Fish ? Water : Sky;
type IEnv2 = IChangeEnv1<Fish | Bird>; // Sky
// 为交叉类型时  不具备分发的能力
type IEnv3 = IChangeEnv<Fish & Bird>; // Water 只会返回满足条件的

// -----------基于条件类型的内置类型

let r = document.querySelector(".root"); // Element | null
// Exclude 排除某个类型
type Exclude<T, K> = T extends K ? never : T;
type ExcludeType = Exclude<number | string | boolean, string>; //  number | boolean
let newR: Exclude<typeof r, null>; // Element

// Extract 取其中类型
type Extract<T, K> = T extends K ? T : never;
type ExtractType = Extract<number | string | boolean, string>; //  string

// NonNullable 排除null
type NonNullable<T> = T extends null | undefined ? never : T;
type NonNullableType = NonNullable<number | null | undefined>; //  number

// -----------基于循环类型的内置类型

interface IPerson {
  name: string;
  info: {
    age: number;
  };
}

// Partial 转可选类型  无法对对象嵌套对象的情况修改
type Partial<T extends object> = {
  //  利用条件判断进行递归判断
  [K in keyof T]?: T[K] extends object ? Partial<T[K]> : T[K];
};
type PartialPerson = Partial<IPerson>; //{ name?: string;}

//  Required 转必选类型
type Required<T extends object> = {
  //  利用条件判断进行递归判断
  [K in keyof T]-?: T[K] extends object ? Required<T[K]> : T[K];
};
type RequirePerson = Required<PartialPerson>;

// Readonly 转只读属性

type Readonly<T extends object> = {
  readonly //  利用条件判断进行递归判断
  [K in keyof T]: T[K] extends object ? Required<T[K]> : T[K];
};
type ReadonlyPerson = Readonly<PartialPerson>;

//0----------------------------------------
interface IAnimal {
  type: string;
  name: string;
  age: number;
  address: string;
}

//  取某个类型中的某些属性
type Pick<T extends object, K extends keyof T> = {
  [key in K]: T[key];
};

type PickType = Pick<IAnimal, "type" | "address">;

//  取某个类型中的其余属性
type Omit<T extends object, K extends keyof T> = {
  [key in Exclude<keyof T, K>]: T[key];
};

type OmitType = Omit<IAnimal, "type">;

//   Record 记录 key：value  场景： 将对象 映射为新对象

let obj = { a: 1, b: 2 };

type Record<T extends keyof any, K> = {
  [R in T]: K;
};
function mapping<K extends keyof any, V, R>(
  obj: Record<K, V>,
  cb: (key: K, value: V) => R
): Record<K, R> {
  let result = {} as Record<K, R>;
  for (let key in obj) {
    result[key] = cb(key, obj[key]);
  }
  return result;
}

let myResult = mapping(obj, (key, value) => {
  return value * 3;
});
